using System;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using XDQ.VAT.EntityFrameworkCore;
using XDQ.VAT.Localization;
using XDQ.VAT.MultiTenancy;
using XDQ.VAT.Web.Menus;
using Microsoft.OpenApi.Models;
using Volo.Abp;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.FeatureManagement;
using Volo.Abp.Identity.Web;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement.Web;
using Volo.Abp.Swashbuckle;
using Volo.Abp.TenantManagement.Web;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.UI;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using XDQ.VAT.Options;
using Volo.Abp.Caching;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Auditing;
using XDQ.VAT.Attributes;
using System.Reflection;
using Volo.Abp.BackgroundJobs.Hangfire;
using Volo.Abp.BackgroundJobs;
using Hangfire;
using Hangfire.SQLite;
using Microsoft.Data.Sqlite;
using XDQ.VAT.Web.BackgroundJobs;
using Volo.Abp.EventBus.RabbitMq;
using System.Collections.Generic;
using System.Net;
using System.Data;

namespace XDQ.VAT.Web
{
    [DependsOn(
        typeof(VATHttpApiModule),
        typeof(VATApplicationModule),
        typeof(VATEntityFrameworkCoreDbMigrationsModule),
        typeof(AbpAutofacModule),
        typeof(AbpIdentityWebModule),
        typeof(AbpAccountWebIdentityServerModule),
        typeof(AbpAspNetCoreMvcUiBasicThemeModule),
        typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
        typeof(AbpTenantManagementWebModule),
        typeof(AbpAspNetCoreSerilogModule),
        typeof(AbpSwashbuckleModule)
        )]
    [DependsOn(typeof(AbpCachingStackExchangeRedisModule))]
    [DependsOn(typeof(AbpBackgroundJobsHangfireModule))]
    [DependsOn(typeof(AbpEventBusRabbitMqModule))]
    public class VATWebModule : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
            {
                options.AddAssemblyResource(
                    typeof(VATResource),
                    typeof(VATDomainModule).Assembly,
                    typeof(VATDomainSharedModule).Assembly,
                    typeof(VATApplicationModule).Assembly,
                    typeof(VATApplicationContractsModule).Assembly,
                    typeof(VATWebModule).Assembly
                );
            });
        }

        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var hostingEnvironment = context.Services.GetHostingEnvironment();
            var configuration = context.Services.GetConfiguration();

            ConfigureUrls(configuration);
            ConfigureBundles();
            ConfigureAuthentication(context, configuration);
            ConfigureAutoMapper();
            ConfigureVirtualFileSystem(hostingEnvironment);
            ConfigureLocalizationServices();
            ConfigureNavigationServices();
            ConfigureAutoApiControllers();
            ConfigureSwaggerServices(context.Services);
            ConfigureCache(context, configuration);
            ConfigureAuditing(context, configuration);
            ConfigureHangfire(context, configuration);
        }

        private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration)
        {
            context.Services.AddHangfire(config =>
            {
                var hangfire = configuration.GetSection("Hangfire");
                if (hangfire.Exists())
                {
                    HangfireStorageOptions options = new HangfireStorageOptions();
                    hangfire.Bind(options);
                    config.UseSqlServerStorage(options.ConnectionString, options);
                }
                else
                {
                    string file = Path.GetFullPath("hangfie.db");
                    SqliteConnectionStringBuilder sqlite = new SqliteConnectionStringBuilder()
                    {
                        DataSource = file,
                        Mode = SqliteOpenMode.ReadWriteCreate,
                        Cache = SqliteCacheMode.Shared,
                    };
                    string connectionStr = sqlite.ToString();
                    config.UseSQLiteStorage(connectionStr);
                    //config.UseSqlServerStorage(ConnectionStr)
                }
            });

        }
        class HangfireStorageOptions : Hangfire.SqlServer.SqlServerStorageOptions
        {
            public string ConnectionString { get; set; }

        }

        private void ConfigureAuditing(ServiceConfigurationContext context, IConfiguration configuration)
        {
            context.Services.Configure<AbpAuditingOptions>(options =>
            {
                var section = configuration.GetSection("Auditing");
                if (section.Exists())
                {
                    section.Bind(options);
                }
                else
                {
                    options.ApplicationName = "傻强";
                    options.IsEnabledForGetRequests = false;
                    options.AlwaysLogOnException = false;
                    options.IsEnabled = true;
                    options.EntityHistorySelectors.Add(new NamedTypeSelector("default", tp =>
                    {
                        return tp.GetCustomAttribute<EnableHistoryAttribute>() != null;
                    }));
                }
            });
        }

        private void ConfigureCache(ServiceConfigurationContext context, IConfiguration configuration)
        {
            //RedisCacheOptions
            var redis = new RedisOptions();
            var section = configuration.GetSection("Redis");
            //section.Get<RedisOptions>();   Get方式 如果没有设置值则为null
            section.Bind(redis); // Bind方式 一定有个值
            Console.WriteLine(redis.ToString());
            if (redis.Enabled == true)
            {
                if (string.IsNullOrEmpty(redis.Configuration))
                {
                    throw new ArgumentNullException(nameof(redis.Configuration), "Please use 'setx Redis__Configuration=xxx ");
                }
                context.Services.Configure<AbpDistributedCacheOptions>((options) =>
                {
                    options.KeyPrefix = "A";
                });
            }
        }

        private void ConfigureUrls(IConfiguration configuration)
        {
            Configure<AppUrlOptions>(options =>
            {
                options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            });
        }

        private void ConfigureBundles()
        {
            Configure<AbpBundlingOptions>(options =>
            {
                options.StyleBundles.Configure(
                    BasicThemeBundles.Styles.Global,
                    bundle =>
                    {
                        bundle.AddFiles("/global-styles.css");
                    }
                );
            });
        }

        private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
        {
            context.Services.AddAuthentication()
                .AddJwtBearer(options =>
                {
                    options.Authority = configuration["AuthServer:Authority"];
                    options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
                    options.Audience = "VAT";
                });
        }

        private void ConfigureAutoMapper()
        {
            Configure<AbpAutoMapperOptions>(options =>
            {
                options.AddMaps<VATWebModule>();
            });
        }

        private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
        {
            if (hostingEnvironment.IsDevelopment())
            {
                Configure<AbpVirtualFileSystemOptions>(options =>
                {
                    options.FileSets.ReplaceEmbeddedByPhysical<VATDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}XDQ.VAT.Domain.Shared"));
                    options.FileSets.ReplaceEmbeddedByPhysical<VATDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}XDQ.VAT.Domain"));
                    options.FileSets.ReplaceEmbeddedByPhysical<VATApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}XDQ.VAT.Application.Contracts"));
                    options.FileSets.ReplaceEmbeddedByPhysical<VATApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}XDQ.VAT.Application"));
                    options.FileSets.ReplaceEmbeddedByPhysical<VATWebModule>(hostingEnvironment.ContentRootPath);
                });
            }
        }

        private void ConfigureLocalizationServices()
        {
            Configure<AbpLocalizationOptions>(options =>
            {
                options.Languages.Add(new LanguageInfo("ar", "ar", "العربية"));
                options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
                options.Languages.Add(new LanguageInfo("en", "en", "English"));
                options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)"));
                options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
                options.Languages.Add(new LanguageInfo("fr", "fr", "Français"));
                options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
                options.Languages.Add(new LanguageInfo("ru", "ru", "Русский"));
                options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
                options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
                options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
                options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
                options.Languages.Add(new LanguageInfo("es", "es", "Español"));
            });
        }

        private void ConfigureNavigationServices()
        {
            Configure<AbpNavigationOptions>(options =>
            {
                options.MenuContributors.Add(new VATMenuContributor());
            });
        }

        private void ConfigureAutoApiControllers()
        {
            Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                options.ConventionalControllers.Create(typeof(VATApplicationModule).Assembly);
            });
        }

        private void ConfigureSwaggerServices(IServiceCollection services)
        {
            services.AddSwaggerGen(
                options =>
                {
                    options.SwaggerDoc("v1", new OpenApiInfo { Title = "VAT API", Version = "v1" });
                    options.DocInclusionPredicate((docName, description) => true);
                    options.CustomSchemaIds(type => type.FullName);
                }
            );
        }

        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {
            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseAbpRequestLocalization();

            if (!env.IsDevelopment())
            {
                app.UseErrorPage();
            }

            app.UseCorrelationId();
            app.UseVirtualFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseJwtTokenMiddleware();

            if (MultiTenancyConsts.IsEnabled)
            {
                app.UseMultiTenancy();
            }

            app.UseUnitOfWork();
            app.UseIdentityServer();
            app.UseAuthorization();
            app.UseSwagger();
            app.UseAbpSwaggerUI(options =>
            {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "VAT API");
            });
            app.UseAuditing();
            app.UseAbpSerilogEnrichers();
            app.UseConfiguredEndpoints();
            app.UseHangfireServer(new BackgroundJobServerOptions()
            {
                ServerName = "TM",
                WorkerCount = 1,
                Queues = new string[] { HangfireOptions.QueueName }
            });
            app.UseHangfireDashboard();
        }


        public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
        {
            base.OnPostApplicationInitialization(context);

            IBackgroundJobManager backgroundJobManager = context.ServiceProvider.GetRequiredService<IBackgroundJobManager>();
            // 尽量不要用 Hangfire.Cron.XX，使用 https://qqe2.com/cron 生成并查看最近10次运行时间
            backgroundJobManager.EnqueueAsync<AlwaysHelloJobArg>("0 0/1 * * *  ? ", new());
            backgroundJobManager.EnqueueAsync<DailySyncAgeJobArg>(Cron.Daily(15, 30), new());
        }
    }
}
